package com.g0dkar.leet.util.common;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.g0dkar.leet.util.reflection.ReflectionUtils;

/**
 * This class provides a checking mechanism to see if a given object graph is completely {@link Serializable}.
 * 
 * @author g0dkar
 *
 */
public class SerializableChecker {
	private Class<?> classToCheck;
	
	public SerializableChecker(Class<?> classToCheck) {
		this.classToCheck = classToCheck;
	}
	
	public SerializableChecker(Object objectToCheck) {
		this(objectToCheck.getClass());
	}
	
	public boolean check() {
		return check(classToCheck, new HashMap<Class<?>, Boolean>());
	}
	
	private boolean check(Class<?> klass, Map<Class<?>, Boolean> previousChecks) {
		if (previousChecks.containsKey(klass)) {
			return previousChecks.get(klass);
		}
		
		boolean isSerializable = klass.isPrimitive() || Serializable.class.isAssignableFrom(klass);
		
		if (!klass.isPrimitive()) {
			previousChecks.put(klass, isSerializable);
		}
		
		Collection<Field> fields = ReflectionUtils.getAllFields(klass);
		
		for (Field field : fields) {
			isSerializable &= Modifier.isTransient(field.getModifiers()) || check(field.getType(), previousChecks);
		}
		
		return isSerializable;
	}
}
